﻿using Instagram.Version2.Helper;
using Instagram.Version2.Models;
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.Geolocation;
using Windows.Graphics.Display;
using Windows.Media.Capture;
using Windows.Media.MediaProperties;
using Windows.Services.Maps;
using Windows.Storage;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=391641

namespace Instagram.Version2
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class PhotoPage : Page
    {
        private MediaCapture captureManager;
        private IStorageFile photoFile;
        private UserModel _user;
        private string _address;

        public PhotoPage()
        {
            this.InitializeComponent();

            this.NavigationCacheMode = NavigationCacheMode.Required;
            _address = "";
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.
        /// This parameter is typically used to configure the page.</param>
        async protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            captureManager = new MediaCapture();

            _user = e.Parameter as UserModel;

            InitCamera();

            _address = await GetLocation();
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);

            captureManager.Dispose();
        }

        private static async Task<DeviceInformation> GetCameraID(Windows.Devices.Enumeration.Panel desiredCamera)
        {
            // get available devices for capturing pictures
            var deviceID = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture))
                .FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredCamera);

            if (deviceID != null) return deviceID;
            else throw new Exception(string.Format("Camera of type {0} doesn't exist.", desiredCamera));
        }

        async private void InitCamera()
        {
            var cameraID = await GetCameraID(Windows.Devices.Enumeration.Panel.Back);

            await captureManager.InitializeAsync(new MediaCaptureInitializationSettings
            {
                StreamingCaptureMode = StreamingCaptureMode.Video,
                PhotoCaptureSource = PhotoCaptureSource.VideoPreview,
                AudioDeviceId = string.Empty,
                VideoDeviceId = cameraID.Id
            });

            var maxResolution = captureManager.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.Photo).Aggregate((i1, i2) => (i1 as VideoEncodingProperties).Width > (i2 as VideoEncodingProperties).Width ? i1 : i2);

            await captureManager.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, maxResolution);

            StartPreview();
        }

        async private void StartPreview()
        {
            // rotate to see preview vertically
            captureManager.SetPreviewMirroring(true);
            capturePreview.Source = captureManager;

            await captureManager.StartPreviewAsync();
        }

        private void GoAway_Click(object sender, RoutedEventArgs e)
        {
            Frame.GoBack();
        }

        async private void TakePhotoBtn_Click(object sender, RoutedEventArgs e)
        {
            // create a file
            photoFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("temp.jpg", CreationCollisionOption.ReplaceExisting);

            // take a photo with choosen Encoding
            await captureManager.CapturePhotoToStorageFileAsync(ImageEncodingProperties.CreateJpeg(), photoFile);
            // show a photo on screen
            imagePreview.Source = new BitmapImage(new Uri(photoFile.Path)); ;  // show image on screen inside Image control defined in XAML

            await captureManager.StopPreviewAsync();
        }

        async private void ShowMessageBox_Click(object sender, RoutedEventArgs e)
        {
            MessageDialog messageDialog = new MessageDialog("Save picture?");

            messageDialog.Commands.Add(new UICommand(
               "Save",
               new UICommandInvokedHandler(this.SavePicture)));

            messageDialog.Commands.Add(new UICommand(
                "Cancel",
                new UICommandInvokedHandler(this.Cancel)));

            await messageDialog.ShowAsync();
        }

        async private void SavePicture(IUICommand command)
        {
            var dialog = new ConfirmFileSaving(captureManager, photoFile, imagePreview.Source, _user, _address);
            await dialog.ShowAsync();

            Cancel(command);
        }

        async private void Cancel(IUICommand command)
        {
            imagePreview.Source = null;

            await photoFile.DeleteAsync();

            await captureManager.StartPreviewAsync();
        }

        async private Task<string> GetLocation()
        {
            var geolocator = new Geolocator();
            geolocator.DesiredAccuracyInMeters = 50;

            try
            {
                var geoposition = await geolocator.GetGeopositionAsync();

                // Location to reverse geocode.
                var location = new BasicGeoposition();
                location.Latitude = geoposition.Coordinate.Latitude;
                location.Longitude = geoposition.Coordinate.Longitude;
                var pointToReverseGeocode = new Geopoint(location);

                // Reverse geocode the specified geographic location.
                var result = await MapLocationFinder.FindLocationsAtAsync(pointToReverseGeocode);

                // If the query returns results, display the name of the town
                // contained in the address of the first result.
                if (result.Status == MapLocationFinderStatus.Success)
                {
                    var address = result.Locations[0].Address;
                    return string.Format("{0}, {1}, {2}, {3}", address.Country, address.Town, address.Street, address.StreetNumber);
                }
                return string.Empty;
            }
            catch (Exception ex)
            {
                if ((uint)ex.HResult == 0x80004004)
                {
                    // the application does not have the right capability or the location master switch is off
                    return "Location  is disabled in phone settings.";
                }
                //else
                {
                    return "Cannot resolve location.";
                }
            }
        }
    }
}
